#pragma once

#include <iostream>
#include <pthread.h>
#include <vector>
#include "Thread.hpp"
#include "Mutex.hpp"
#include "Cond.hpp"
#include <queue>
#include "Log.hpp"
#include <functional>
#include <string>

namespace ThreadPoolModule
{
    using namespace ThreadModule;
    using namespace MutexModule;
    using namespace CondModule;
    using namespace LogModule;

    const int defualt_thread_num = 3;
    template <typename T>
    class ThreadPool
    {
    private:
        bool Empty()
        {
            return _tasks.empty();
        }
        void HandlerTasks(const std::string &name)
        {

            while (true)
            {
                T _func;
                {
                    MutexGuard lock(_mutex);

                    while (Empty() && _isrunning)
                    {
                        _wait_num++;
                        _cond_threads.Wait(_mutex);
                        _wait_num--;
                    }

                    if (Empty() && !_isrunning)
                        break;

                    _func = _tasks.front();
                    _tasks.pop();
                }
                LOG(LogLevel::INFO) << "线程-" << name << "正在执行任务";
                _func();
            }
        }

    public:
        ThreadPool(int num = defualt_thread_num)
            : _thread_num(num), _wait_num(0), _isrunning(false)
        {
            for (int i = 0; i < _thread_num; i++)
            {
                _threads.emplace_back(std::bind(&ThreadPool<T>::HandlerTasks, this, std::placeholders::_1));
            }
        }

        static ThreadPool<T> *GetPool(int num = defualt_thread_num)
        {
            if (thread_pool == nullptr)
            {
                MutexGuard lock(_lock);

                if (thread_pool == nullptr)
                    thread_pool = new ThreadPool(num);
            }

            return thread_pool;
        }

        void Equeue(T &in)
        {
            MutexGuard lock(_mutex);
            if (_isrunning)
            {
                _tasks.push(in);

                if (_wait_num)
                {
                    _cond_threads.Signal();
                }
            }
        }

        void Start()
        {
            if (_isrunning)
                return;

            _isrunning = true;

            for (Thread &thread : _threads)
            {
                thread.Start();
            }
        }

        void Wait()
        {
            _isrunning = false;
            for (Thread &thread : _threads)
            {
                thread.Join();
            }
        }

        void Stop()
        {
            MutexGuard lock(_mutex);

            _isrunning = false;

            if (_wait_num > 0)
                _cond_threads.AllSignal();
        }

    private:
        std::vector<Thread> _threads;
        int _thread_num;
        int _wait_num;

        Mutex _mutex;

        Cond _cond_threads;

        std::queue<T> _tasks;
        bool _isrunning;

        static ThreadPool<T> *thread_pool;
        static Mutex _lock;
    };

    template <typename T>
    ThreadPool<T> *ThreadPool<T>::thread_pool = nullptr;
    template<typename T>
    Mutex ThreadPool<T>::_lock;

}